<template>
  <div class="blog-chat">
    <ElCard v-if="!dialogVisible" class="box-card blog-chat--wrap">
      <template #header>
        <div class="clearfix">
          <span>欢迎你 {{ nickName }} 来到聊天室</span>
        </div>
      </template>
      <div
        v-for="(chat, idx) in chatList"
        :key="idx + chat.time"
        :class="{ text: true, item: true, 'blog-chat--item': true, [getPosition(chat)]: true }"
      >
        <div v-if="chat.nickName" class="blog-chat--nickName">
          {{ chat.nickName }}
        </div>
        <div class="blog-msg--wrap">
          <div v-if="chat.time" class="blog-chat--time">
            {{ chat.time }}
          </div>
          <div v-if="chat.msg" class="blog-chat--msg">
            {{ chat.msg }}
          </div>
        </div>
      </div>
    </ElCard>
    <div class="blog-send--msg">
      <ElInput
        v-model="msg"
        maxlength="60"
        placeholder="请输入60字以内的内容"
        class="blog-input--msg"
        @keydown.enter="sendMsg"
      />
      <ElButton class="blog-btn--submsg" @click="sendMsg">提交</ElButton>
    </div>
    <!-- 
      是否显示通过v-model
      本次使用是否会发生改变而创建如此
      表示滚动条是否存在, 表示整个wrap内容是否存在, 如果存在就表示, 能获取到
      但是在什么时机进行获取, onMount, 坑没有被渲染content, 设置响应式, 使用vueUse
    -->
    <ElDialog v-model="dialogVisible" title="设置昵称" width="30%">
      <ElInput v-model="writeNickName" />
      <template v-slot:footer>
        <span class="dialog-footer">
          <ElButton @click="dialogVisible = false">取 消</ElButton>
          <ElButton type="primary" @click="addNickName">确 定</ElButton>
        </span>
      </template>
    </ElDialog>
  </div>
</template>

<script setup lang="ts">
/*
  实现socket小型聊天室
  1. 大体框架
    创建名称: input(如果已经登录, 直接获取userInfo的nickName | 没有登录, 弹出对话框, 请用户填入需要的昵称)
    昵称 + 时间 + msg(别人)
                                        昵称 + 时间 + msg(自己)
                    
    msg输入框 + 发送按钮
                  昵称 + 登录 | 登出
  2. 数据结构: 
    所有的交流添加到一个对象中, 使用type分行为
    msg, nickName, type类型(msg | action), isMe是否使用户自己, isLogin是否已经登录登出
    
  3. 封装socket方法
    1. client端
      emit 点击登录, 需要emit login提示服务端
           点击登出 emit logout
           发送信息 send, 传递msg + nickName + 时间
      on serverMsg, 接收发过来的信息, 存放到 列表中
         serverLogged 结构发来的信息, 将行为存放到列表中
         serverLogout 将isLogin设置为false

    2. server端
      on logged 用户已经登录, push用户列表
         logout 用户已经登出, 将用户nickName删除
         send 用户发送信息, 接收信息, 将信息广播出去(不进行存储)
      emit
        serverMsg
        serverLogged, 传入用户的nickName
        serverLogout 传入用户的nickName

 socket 判断, 首先是样式问题
 然后是内容上的问题, 关于socket.io的判断机制, serverLog, 并没有触发为false, 然后触发新内容, 关于是否log
*/
import { ElNotification } from 'element-plus'
import { ref, computed, onMounted, onBeforeUnmount, nextTick } from 'vue'

import { useSocket } from '@/store/socket'
import { useUser } from '@/store/user'
import formateDate from '@/unit/formateDate'
let socket = useSocket()
// 在main中只挂在一个socket会话
let user = useUser()
let chatList = ref<any>([])
let dialogVisible = ref<boolean>(true)
let msg = ref<string>('')
let nickName = ref<string>('')
let writeNickName = ref<string>('')
let uid = computed(() => {
  return user?.userInfo?._id || ''
})
onMounted(() => {
  // TODO, 修改live2d的位置
  // this.$store.commit('LIVE2D_ISRIGHT_TRUE')

  socket.getIo(true)
  socket.$io?.on('connect', () => {
    console.log('连接建立成功')
  })
  socket.$io?.on('serverMsg', serverMsg)
  socket.$io?.on('serverLog', serverLog)
  socket.$io?.on('hasNickName', hasNickName)
  nickName.value = user.userInfo?.nickName || ''
  writeNickName.value = nickName.value
})
onBeforeUnmount(() => {
  socket.$io?.emit('leaveChat')
  // TODO, live2D
  // this.$store.commit('LIVE2D_ISRIGHT_FALSE')
})
function hasNickName({ msg }) {
  ElNotification({
    title: '警告',
    message: `${msg}`,
    type: 'warning',
  })
}
function getPosition(item) {
  let msgPosition = 'left'
  if (item.type === 'action') {
    msgPosition = 'center'
  }
  if (item.isMe) {
    msgPosition = 'right'
  }
  return msgPosition
}
// islogin的目的是为了表示是否登录, 显示nickName?
function addChat({ nickName = '', type = 'msg', msg = '', isMe = false, time = formateDate() } = {}) {
  // 局部属性
  chatList.value.push({ nickName, type, msg, isMe, time })
  console.log('show')
  nextTick(overScroll)
}
function serverMsg({ msg = '', nickName = '' } = {}) {
  addChat({ nickName, msg })
}
function serverLog({ nickName, isLogin }) {
  dialogVisible.value = false
  let state = isLogin ? '进入' : '离开'
  addChat({ type: 'action', msg: `${nickName}-${state}了聊天室` })
}
function addNickName() {
  nickName.value = writeNickName.value
  socket.$io?.emit('enterChat', { uid: uid.value, nickName: nickName.value })
}

function sendMsg() {
  if (!msg.value?.trim()) {
    return false
  }

  // console.log(.scrollTo(0, 1000))
  // if (this.$refs['scrollView']) {
  //   // 通过查看组件的数据和方法, 拿到自己有用的东西, 就可以进行调度执行等操作
  //   let overHeight = this.$refs['scrollView'].$refs.scrollContent.scrollHeight
  //   this.$refs['scrollView'].scrollTo({ x: 0, y: overHeight }, 10)
  // }

  let data = {
    msg: msg.value,
    nickName: nickName.value,
    isMe: true,
  }
  addChat(data)
  socket.$io.emit('send', data)
  msg.value = ''
  nextTick(overScroll)
}
function overScroll()  {
    // 如果发送信息, 就回到最低层
    let cardWrap = document.querySelector('.blog-chat--wrap .el-card__body')
    cardWrap?.scrollTo(0, cardWrap.scrollHeight - cardWrap.clientHeight)
  }
</script>

<style lang="less">
@import url('@/assets/css/variable.less');

.blog-chat--wrap {
  display: flex;
  flex-direction: column;
  height: 100%;

  & .el-card__body {
    box-sizing: border-box;
    height: calc(60vh - 50px);
    overflow: auto;
  }
}

.blog-chat--item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  padding: @padding-space * 2 0;

  &.center {
    align-items: center;

    & .blog-msg--wrap {
      display: flex;
      width: auto;
      padding: @padding-space;
      margin: 0;
      font-size: 14px;
      line-height: 20px;
      color: @font-modifier-color;
      border-radius: none;
      box-shadow: none;
    }

    & .blog-chat--time {
      padding-right: @padding-space;
    }
  }

  &.right {
    align-items: flex-end;
  }
}

.blog-send--msg {
  display: flex;
}

/* stylelint-disable-next-line no-descending-specificity */
.blog-msg--wrap {
  width: 200px;
  padding: @padding-space;
  margin: @padding-space @padding-space * 6;
  line-height: 20px;
  word-wrap: break-word;
  border-radius: @padding-space;
  box-shadow: 0 0 @padding-space @line-theme-color;
}
</style>
